const domExp = /<[a-zA-Z0-9]+\s*[^>]+>/gim
const domExpTagAttr = /<([a-zA-Z0-9]+)\s*([^>]+)*>/gim
const text = /\s*{\s*{\s*([\.0-9A-Za-z]+)\s*}\s*}\s*/gim
const query = (selector) => {
    return selector.nodeType ? selector : document.querySelector(selector)
}

const createElement = (tag, ops) => {
    const elem = document.createElement(tag);
    if (elem.nodeType === 1)
        Object.keys(ops).forEach(n => {
            elem.setAttribute(n, ops[n])
        })
    return elem
}

class VNode {
    constructor(ops) {
        this.update(ops)
        return this;
    }
    tag = undefined;
    children = [];
    ref = undefined;
    data = Object.create(null);
    elem = undefined;
    parent = undefined;
    methods = Object.create(null);
    update(ops) {
        Object.assign(this, ops)
        return this;
    }
}

const vnodes = []

const setAttrs = (vnode, node) => {
    if (!node.attributes) return;
    const data = Object.create(null);
    Object.keys(node.attributes).forEach(attr => {
        const name = node.attributes[attr].name, value = node.attributes[attr].value;
        Object.assign(data, {
            [name]: value
        })
    })
    vnode.update({ data })
}

const eachElements = (elem, parent) => {
    const temp = new VNode({
        tag: elem.nodeType === 3 ? 'text' : elem.tagName,
        ref: elem.getAttribute && elem.getAttribute('ref'),
        elem,
        parent
    })
    parent && parent.children.push(temp)
    vnodes.push(temp)
    setAttrs(temp, elem)
    elem.childNodes.forEach(node => {
        if (node.childNodes.length > 0) {
            eachElements(node, temp)
        } else {
            const item = new VNode({
                tag: node.nodeType === 3 ? 'text' : node.tagName,
                ref: node.getAttribute && node.getAttribute('ref'),
                elem: node,
                parent: temp,
            })
            node.nodeType === 3 && item.update({
                data: {
                    textContent: node.textContent
                }
            })
            temp && temp.children.push(item)
            vnodes.push(item)
            setAttrs(item, node)
        }
    })
}

class Tmpl {
    constructor(ops) {
        this.options = ops
        return this;
    }
    #options = {};
    resolve() {
        const that = this;
        let elem = query(this.options.elem)
        elem = elem.cloneNode(true)
        eachElements(elem.content.cloneNode(true).children[0]);
        this.data = this.options.data()
        Object.keys(this.data).forEach(item => {
            const value = that.data[item]
            const data = { value, elem: [] }
            vnodes.forEach(vnode => {
                Object.keys(vnode.data).forEach(key => {
                    const reg = RegExp("\\\s*{\\\s*{\\\s*" + item + "\\\s*}\\\s*}\\\s*", 'gim'),
                        regKey = RegExp(item + '\\\s+', 'gim')
                    if (reg.test(vnode.data[key]) || (/\:/.test(key) && regKey.test(vnode.data[key])))
                        data.elem.push(vnode)
                })
            })
            that.#options['_' + item] = data
            Object.defineProperty(that.data, item, {
                get() {
                    return that.#options['_' + item].value
                },
                set(val) {
                    that.#options['_' + item].value = val;

                    //that.resolve().render(that.root, true)
                }
            })
        })
        return this;
    }
    render(id, bool) {
        this.root = query(id)
        bool ? this.root.replaceChild(this.elem, this.root.children[0]) : this.root.append(this.elem)
        console.log(vnodes)
        return this;
    }
}